package org.apache.ocean;

import java.util.concurrent.*;
import org.apache.lucene.document.*;
import java.util.*;
import org.apache.lucene.search.Query;
import org.apache.ocean.*;
import java.util.concurrent.locks.*;
import org.apache.ocean.*;

/**
 *
 * @author jasonr
 */
public class ResultsCache {
  private LinkedHashMap<QueryKey,Results> resultsMap;
  private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
  SearchService searchService;
  
  public ResultsCache(int maxSize, SearchService searchService) {
    resultsMap = new LRUMap<QueryKey,Results>(maxSize, maxSize);
    this.searchService = searchService;
  }
  
  public class LRUMap<K,V> extends LinkedHashMap<K,V> {
    public int maxSize;
    
    public LRUMap(int size, int maxSize) {
      super(size);
      this.maxSize = maxSize;
    }
    
    protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
      if (size() > maxSize) return true;
      return false;
    }
  }
  
  public SearchResponse processSearchResponse(SearchRequest searchRequest) throws Exception {
    SearchResponse searchResponse = new SearchResponse();
    //QueryKey queryKey = searchRequest.toQueryKey();
    //Results results = getResults(queryKey);
    //if (results == null) return null;
    
    //searchResponse.documents = searchService.getDocumentsNoLock(results.list, searchRequest.fields);
    //return searchResponse;
    return null;
  }
  /**
  public boolean add(SearchRequest searchRequest, SearchResponse searchResponse) throws Exception {
    IndexSchema indexSchema = searchService.getIndexSchema();
    QueryKey queryKey = searchRequest.toQueryKey();
    if (resultsMap.containsKey(queryKey)) return false;
    
    List<IDVersion> idVersions = new ArrayList<IDVersion>(searchResponse.documents.size());
    for (DocID docID : searchResponse.documents) {
      Long id = ClusterUtil.getID(docID.document, indexSchema);
      Long version = ClusterUtil.getVersion(docID.document, indexSchema);
      //idVersions.add(new IDVersion(id, version));
    }
    LockUtil.lock(lock.writeLock());
    try {
      Results results = new Results(idVersions, searchResponse.start, searchResponse.numfound, searchResponse.maxScore);
      resultsMap.put(queryKey, results);
      return true;
    } finally {
      lock.writeLock().unlock();
    }
  }
  **/
  public Results getResults(QueryKey queryKey) {
    LockUtil.lock(lock.readLock());
    try {
      return resultsMap.get(queryKey);
    } finally {
      lock.readLock().unlock();
    }
  }
  
  public void remove(IDVersion idVersion) {
    LockUtil.lock(lock.writeLock());
    try {
      List<QueryKey> queryKeysToRemove = new ArrayList<QueryKey>();
      for (Map.Entry<QueryKey,Results> entry : resultsMap.entrySet()) {
        Results results = entry.getValue();
        if (results.contains(idVersion)) {
          queryKeysToRemove.add(entry.getKey());
        }
      }
      for (QueryKey queryKey : queryKeysToRemove) {
        resultsMap.remove(queryKey);
      }
    } finally {
      lock.writeLock().unlock();
    }
  }
  
  public static class Results {
    public Set<IDVersion> set;
    public List<IDVersion> list;
    public Integer start;
    public Integer numFound;
    public Float maxScore;
    
    public Results(List<IDVersion> list, Integer start, Integer numfound, Float maxScore) throws Exception {
      this.list = list;
      this.start = start;
      this.numFound = numFound;
      this.maxScore = maxScore;
      set = new HashSet<IDVersion>(list.size());
      for (IDVersion idVersion : list) {
        set.add(idVersion);
      }
    }
    
    public boolean contains(IDVersion idVersion) {
      return set.contains(idVersion);
    }
  }
}
